#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>

int main(int argc, char *argv[])
{ 
    // get port to run on, and IP+port to communicate with from command line
    if(argc!=4)
    {
        fprintf(stderr, "requires localport remoteip remoteport\n");
        exit(1);
    }
    int port_number = atol(argv[1]);
    char * remote = argv[2];
    int remote_port = atol(argv[3]);

    // Step 1 Look up server to get numeric IP address
    hostent * record = gethostbyname(remote);
    if(record==NULL)
    {
        herror("gethostbyname failed");
        exit(1);
    }
    in_addr *addressptr = (in_addr *) record->h_addr;

    // Step 2 Create a socket
    int main_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if(main_socket<0)
    {
        perror("socket creation");
        exit(1);
    }

    // Step 3 Create a sockaddr_in to describe the local port
    sockaddr_in local_info;
    // local_info.sin_len = sizeof(local_info);
    local_info.sin_family = AF_INET;
    local_info.sin_addr.s_addr = htonl(INADDR_ANY);
    local_info.sin_port = htons(port_number);

    // Step 4 Bind the socket to the port
    int r = bind(main_socket, (sockaddr *) &local_info, sizeof(local_info));
    if(r<0)
    {
        perror("bind");
        exit(1);
    }
    printf("ready\n");

    // Step 5 Create a sockaddr_in to describe the remote application
    sockaddr_in remote_info;
    // remote_info.sin_len = sizeof(remote_info);
    remote_info.sin_family = AF_INET;
    remote_info.sin_addr = *addressptr;
    remote_info.sin_port = htons(remote_port);

    // Step 6 Send a message
    const char *message1="Hello you\n";
    r=sendto(main_socket, message1, strlen(message1), MSG_EOR, (sockaddr *) &remote_info, sizeof(remote_info));
    if(r<0)
    {
        perror("sendto");
        exit(1);
    }
    printf("sent %d characters of %s\n", r, message1);

    // Step 7 Wait for a message to be received
    char buffer[100];
    struct sockaddr_in incoming_info;
    unsigned int socklen = sizeof(incoming_info);
    r=recvfrom(main_socket, &buffer, sizeof(buffer)-1, 0, (sockaddr *) &incoming_info, &socklen);
    if(r<0)
    {
        perror("recvfrom");
        exit(1);
    }
    buffer[r]=0;
    printf("from %s port %d, %d characters: %s\n", inet_ntoa(incoming_info.sin_addr), ntohs(incoming_info.sin_port), r, buffer);

    // Duplicate for step 6, but with a different message
    const char *message2="Hello again\n";
    r=sendto(main_socket, message2, strlen(message2), MSG_EOR, (sockaddr *) &remote_info, sizeof(remote_info));
    if(r<0)
    {
        perror("sendto");
        exit(1);
    }
    printf("sent %d characters of %s\n", r, message2);

    // Step 8 Close the socket and exit
    close(main_socket);

    return 0;
}
